﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Windows.Forms.DataVisualization.Charting;
using System.Linq;
using JetBrains.Annotations;
using Kaleida.ServiceMonitor.Model.Statistics;

namespace Kaleida.ServiceMonitor.UI
{
    public partial class OperationStatisticsControl : UserControl
    {
        private bool updatingUI;
        private const string NullIndicator = "-";
        private readonly ProcessingStatistics statistics;

        public OperationStatisticsControl(ProcessingStatistics statistics)
        {
            this.statistics = statistics;
            InitializeComponent();
            UpdateControlsBasedOnLogarithmicAxisSetting();
            UpdateUI();
        }

        [NotNull]
        public ProcessingStatistics Statistics
        {
            get {return statistics;}
        }

        public void UpdateUI()
        {
            if (updatingUI)
                return;

            lock (this)
            {
                updatingUI = true;
                SuspendLayout();

                tbDescription.Text = statistics.Description;

                tbRequestCount.Text = statistics.ProcessedCount.ToString("0");
                tbSuccessCount.Text = statistics.SuccessCount.ToString("0");
                tbFailureCount.Text = statistics.FailureCount.ToString("0");
                tbSuccessRate.Text = GetSuccessRateString();

                tbMeanRequestMs.Text = GetMillisecondText(statistics.MeanProcessingTime);
                tbMinRequestMs.Text = GetMillisecondText(statistics.MinimumProcessingTime);
                tbMaxRequestMs.Text = GetMillisecondText(statistics.MaximumProcessingTime);
                tbRecentRequestMs.Text = GetMillisecondText(statistics.MostRecentProcessingTime);

                var percentiles = statistics.GetResponseTimePercentiles(new[] {90m, 99m, 99.9m, 99.99m});
                tb1Nine.Text = GetMillisecondText(percentiles[0].Value);
                tb2Nines.Text = GetMillisecondText(percentiles[1].Value);
                tb3Nines.Text = GetMillisecondText(percentiles[2].Value);
                tb4Nines.Text = GetMillisecondText(percentiles[3].Value);

                var points = statistics.GetResponseTimeDistribution();
                UpdateChartUI(points);

                ResumeLayout();
                updatingUI = false;
            }
        }

        private string GetSuccessRateString()
        {
            return statistics.ProcessedCount == 0
                ? NullIndicator
                : (((double)statistics.SuccessCount)/statistics.ProcessedCount).ToString("0.000%");
        }

        private static string GetMillisecondText(TimeSpan? value)
        {
            return value == null ? NullIndicator : value.Value.TotalMilliseconds.ToString("0");
        }

        private void UpdateChartUI(IList<DistributionPoint> points)
        {
            chtDistribution.Series.Clear();

            var series = new Series
                             {
                                 IsXValueIndexed = false,
                                 ChartType = SeriesChartType.Column,
                                 MarkerSize = 3,
                                 MarkerStyle = MarkerStyle.None,
                             };

            foreach (var point in points)
            {
                var dataPoint = new DataPoint(point.TimeMs, point.Count);
                series.Points.Add(dataPoint);
            }

            chtDistribution.Series.Add(series);

            var chartArea = chtDistribution.ChartAreas[0];
            chartArea.AxisX.IsLogarithmic = chkLogXAxis.Checked && points.Any();
            chartArea.AxisX.LogarithmBase = (double) nudLogarithmBase.Value;

            chartArea.RecalculateAxesScale();
        }

        private void chkLogXAxis_CheckedChanged(object sender, EventArgs e)
        {
            UpdateControlsBasedOnLogarithmicAxisSetting();
        }

        private void UpdateControlsBasedOnLogarithmicAxisSetting()
        {
            nudLogarithmBase.Enabled = chkLogXAxis.Checked;
        }
    }
}
